// Draw random coloured smooth (anti-aliased) rounded rectangles on the TFT

#include <TFT_eSPI.h>
#include <TJpg_Decoder.h>

#include <ArduinoJson.h>

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
 
#define ssid      "ziroom3202" //这里改成你的设备当前环境下WIFI名字
#define password  "4001001111"          //这里改成你的设备当前环境下WIFI密码
 
WiFiUDP Udp;//实例化WiFiUDP对象
unsigned int localUdpPort = 60000;  // 自定义本地监听端口


#include "font/ZdyLwFont_20.h"


#include "img/cpu.h"
#include "img/ram.h"
#include "img/net.h"
#include "img/right.h"

TFT_eSPI tft = TFT_eSPI();
TFT_eSprite clk = TFT_eSprite(&tft);
#define LCD_BL_PIN 5    //LCD背光引脚
#define NUM_LEN 26
uint16_t bgColor = 0x0000;

//其余状态标志位
int LCD_Rotation = 0;   //LCD屏幕方向
int LCD_BL_PWM = 50;//屏幕亮度0-100，默认50

String json;

float data_up[NUM_LEN]={};

float data_dw[NUM_LEN]={};

int data_up_max = 0;
int data_dw_max = 0;

void setup(void) {
  pinMode(LCD_BL_PIN, OUTPUT);
  analogWrite(LCD_BL_PIN, 1023 - (LCD_BL_PWM*10));
  
  tft.begin(); /* TFT init */
  tft.invertDisplay(1);//反转所有显示颜色：1反转，0正常
  tft.setRotation(LCD_Rotation);
  tft.fillScreen(0x0000);
  tft.setTextColor(TFT_BLACK, bgColor);

  tft.setCursor(0, 0);
  // 绘制表格的每一行

  TJpgDec.setJpgScale(1);
  TJpgDec.setSwapBytes(true);
  TJpgDec.setCallback(tft_output);
  initUdpService();
  // tft.init();
  // tft.fillScreen(TFT_BLACK); // Background is black
  TJpgDec.drawJpg(105,20,net, sizeof(net));  //net图标
  TJpgDec.drawJpg(15,20,right, sizeof(right));  //箭头图标
  TJpgDec.drawJpg(205,20,right, sizeof(right));  //箭头图标
  // drowUpPacke(100.0,100.0);
  drowGrid(20,50,220,50,tft.color565(5, 255, 250));
  drowCPU(0.0);
  drowRAM(0.0);
  tft.drawFastHLine(0, 220, 240, tft.color565(5, 255, 250)); //横线(快速)
  drowPidInfoKey();
    
}

void loop() {
  // tft.fillScreen(TFT_BLACK);
  


  readUdpPacke();

  // drowGrid(20,100,220,50,tft.color565(255, 250, 5));

  // delay(200);
}

/**
 * 初始化UDP服务
 *
 */
void initUdpService(){
  Serial.begin(115200);//打开串口
  Serial.println();
 
  Serial.printf("正在连接 %s ", ssid);
  WiFi.begin(ssid, password);//连接到wifi
  while (WiFi.status() != WL_CONNECTED)//等待连接
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("连接成功");
 
  if(Udp.begin(localUdpPort)){//启动Udp监听服务
    Serial.println("监听成功");
    //打印本地的ip地址，在UDP工具中会使用到
    //WiFi.localIP().toString().c_str()用于将获取的本地IP地址转化为字符串   
    Serial.printf("现在收听IP：%s, UDP端口：%d\n", WiFi.localIP().toString().c_str(), localUdpPort);
  }else{
    Serial.println("监听失败");
  }
}

/**
 * 读取UDP数据包
 *
 */
void readUdpPacke(){
  int packetSize = Udp.parsePacket();//获得解析包
  // Serial.printf("当前UDP解析包字节数: %d\n", packetSize);
  if(Udp.available()){//判断是否有UDP数据包
    char incomingPacket[500];  // 存储Udp客户端发过来的数据
    char * aa = incomingPacket;
    int len = Udp.read(incomingPacket, 500);
    json = String(aa);
    // Serial.printf("len：%d\n",  len);
    prensJson();
  }
}

/**
 * 读取解析json数据
 *
 */
void prensJson(){
  StaticJsonDocument<500> doc;
  DeserializationError error = deserializeJson(doc, json);
  if (error) {
  Serial.print(F("deserializeJson() failed: "));
  Serial.println(error.f_str());
  return;
  }
  int type = doc["type"];
  float cpu = doc["cpu"];
  float ram = doc["ram"];
  float upsp = doc["upsp"];
  float downsp = doc["downsp"];
  if(type==1){
    drowUpPacke(upsp,downsp);
    drowCPU(cpu);
    drowRAM(ram);
    drowGrid(20,50,220,50,tft.color565(5, 255, 250));
  }else if(type==2){
    drowPidInfoKey();
    for(int i=0;i<4;i++){
      const char* street = doc["pid"][i]["name"];
      int32_t pid = doc["pid"][i]["pid"];
      int32_t cpu_percent = doc["pid"][i]["cpu_percent"];
      drowPidInfo(i,street,pid,cpu_percent);
    }
  }
}

void drowPidInfoKey(){
  tft.fillRect(25,225, 200, 20, bgColor);
  tft.setCursor(25,225);
  tft.setTextSize(1);
  tft.print("soft_name");
  tft.setCursor(150,225);
  tft.print("pid");
  tft.setCursor(200,225);
  tft.print("cpu");
}


void drowPidInfo(int index,const char* street,int32_t pid,int32_t cpu_percent){
  int32_t sy = 240+index*15;
  tft.fillRect(25,sy, 200, 20, bgColor);
  tft.setCursor(25,sy);
  tft.setTextSize(1);
  tft.print(street);
  tft.setCursor(150,sy);
  tft.print(pid);
  tft.setCursor(200,sy);
  tft.print(cpu_percent);
}

/**
 * 绘制上行下行数据
 *
 */
void drowUpPacke(float aa,float bb){

  tft.fillRect(37,28, 43, 20, bgColor);
  // 设置文本颜色与背景色
  tft.setTextColor(TFT_WHITE, bgColor);
  // 设置文本显示坐标，默认以文本左上角为参考点，可以改变参考点
  tft.setCursor(37,28);
  tft.setTextSize(1);
  tft.print(data_up_max>0?aa/1024:aa);
  tft.setCursor(80,28);
  tft.print(data_up_max>0?"mbps":"kbps");

  tft.fillRect(137,28, 43, 20, bgColor);
  tft.setCursor(137,28);
  tft.print(data_dw_max>0?bb/1024:bb);
  tft.setCursor(180,28);
  tft.print(data_dw_max>0?"mbps":"kbps");
  drowPacke(aa,bb);
}

/**
 * 绘制网格
 * aa 上行数据
 * bb 下行数据
 */
void drowPacke(float aa,float bb){
  for(int i=0;i<NUM_LEN-1;i++){
    data_up[i]=data_up[i+1];
    data_dw[i]=data_dw[i+1];
  }
  if(aa>1024){
    data_up_max = NUM_LEN;
  }
  if(bb>1024){
    data_dw_max = NUM_LEN;
  }
  data_up[NUM_LEN-1] = aa;
  data_dw[NUM_LEN-1] = bb;
}


/**
 * 绘制CPU
 *
 */
void drowCPU(float aa){
  int arg = (aa/100)*270;
  if(arg>270) arg = 270;
  if(arg<1) arg = 1;
  tft.drawSmoothArc(70,165,45,38,arg,270,tft.color565(5, 255, 250),true);
  tft.drawSmoothArc(70,165,45,38,0,arg,tft.color565(255,250,5),true);
  TJpgDec.drawJpg(85,180,cpu, sizeof(cpu));  //cpu图标

  clk.setColorDepth(8);
  clk.loadFont(ZdyLwFont_20);
  clk.createSprite(70, 24); 
  clk.fillSprite(bgColor);
  clk.setTextDatum(CC_DATUM);
  clk.setTextColor(TFT_WHITE, bgColor); 
  //  clk.drawString(sk["SD"].as<String>(),28,13);
  clk.drawFloat(aa,1,25,13);
  clk.drawString("%",60,13);
    //clk.drawString("100%",28,13);
  clk.pushSprite(35,153);
  clk.deleteSprite();
}

/**
 * 绘制RAM
 *
 */
void drowRAM(float aa){
  int arg = (aa/100)*270;
  if(arg>270) arg = 270;
  if(arg<1) arg = 1;
  tft.drawSmoothArc(170,165,45,38,arg,270,tft.color565(5, 255, 250),true);
  tft.drawSmoothArc(170,165,45,38,0,arg,tft.color565(255,250,5),true);
  TJpgDec.drawJpg(185,180,ram, sizeof(ram));  //RAM图标
  clk.setColorDepth(8);
  clk.loadFont(ZdyLwFont_20);
  clk.createSprite(70, 24); 
  clk.fillSprite(bgColor);
  clk.setTextDatum(CC_DATUM);
  clk.setTextColor(TFT_WHITE, bgColor); 
  //  clk.drawString(sk["SD"].as<String>(),28,13);
  clk.drawFloat(aa,1,25,13);
  clk.drawString("%",60,13);
    //clk.drawString("100%",28,13);
  clk.pushSprite(135,153);
  clk.deleteSprite();
}

/**
 * 绘制网格
 *
 */
void drowGrid(int32_t sx,int32_t sy,int32_t w,int32_t h,int32_t color){
  tft.fillRect(sx,sy, w, h, bgColor);
  for(int row=0;row<6;row++){
      int y = sy+row*10;
      drowPointHLine(sx,y,w,color);
  }
  drowVLineInterval(sx,sy,w,h,color,13);
  tft.drawFastHLine(sx-5, sy-5, 10, color); //横线(快速)
  tft.drawFastHLine(sx-5, sy+h+5, 10, color); //横线(快速)
  tft.drawFastVLine(sx-5, sy-5, h+10, color); //竖线(快速)
  tft.drawFastVLine(w+5, sy-5, h+10, color); //竖线(快速)
  tft.drawFastHLine(w-5, sy-5, 10, color); //横线(快速)
  tft.drawFastHLine(w-5, sy+h+5, 10, color); //横线(快速)

  drowNetWrokLine(sx,sy,w,h,color);
}

void drowNetWrokLine(int32_t sx,int32_t sy,int32_t w,int32_t h,int32_t color){
  data_up_max--;
  data_dw_max--;
  if(data_dw_max < 0)data_dw_max = 0;
  if(data_up_max < 0)data_up_max = 0;
    //计算间隔
  int32_t ww = w/NUM_LEN;
  int32_t unit_up = data_up_max==0?1024:1024*100;
  int32_t unit_dw = data_dw_max==0?1024:1024*100;
  int32_t hh = sy+h;
  for(int i=0;i<NUM_LEN-1;i++){
    int32_t ux0 = sx+ww*i;
    int32_t uy0 = hh-(data_up[i]/unit_up*h);
    int32_t ux1 = sx+ww*(i+1);
    int32_t uy1 = hh-(data_up[i+1]/unit_up*h);
    if(uy0<sy)uy0=sy;
    if(uy1<sy)uy1=sy;
    tft.drawLine(ux0, uy0, ux1, uy1, color);
    int32_t dx0 = sx+ww*i;
    int32_t dy0 = hh-(data_dw[i]/unit_up*h);
    int32_t dx1 = sx+ww*(i+1);
    int32_t dy1 = hh-(data_dw[i+1]/unit_up*h);
    if(dy0<sy)dy0=sy;
    if(dy1<sy)dy1=sy;
    tft.drawLine(dx0, dy0, dx1, dy1, tft.color565(255,250,5));
  }
}


//TFT屏幕输出函数
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap){
  if ( y >= tft.height() ) return 0;
  tft.pushImage(x, y, w, h, bitmap);
  // Return 1 to decode next block
  return 1;
}

// 绘制间隔竖线
void drowVLineInterval(int32_t sx,int32_t sy,int32_t w,int32_t h,int32_t color,int32_t num){
  int interval = w/num;
  for(int i=0;i<num;i++){
    int ox = sx+i*interval;
    tft.drawFastVLine(ox, sy, h, color); //竖线(快速)
  }
  
}
//绘制点状横线
void drowPointHLine(int32_t sx,int32_t sy,int32_t w,int32_t color){
 for (int row = sx; row <= w; row++) {  
    if(!(row%3))tft.drawPixel(row, sy, color);
  }  
}
//绘制点状竖线
void drowPointVLine(int32_t sx,int32_t sy,int32_t w,int32_t color){
 for (int row = sx; row <= w; row++) {  
    if(!(row%3))tft.drawPixel(sy,row, color);
  }  
}



